﻿using Hsp.WebNovels.App.Models;
using HtmlAgilityPack;
using Microsoft.AspNetCore.Builder;
using Microsoft.Extensions.Configuration;
using SqlSugar;
using System.Net;
using System.Text.RegularExpressions;
using System.Text;
using Hsp.WebNovels.App.Utility;
using System.Diagnostics;
using System.Collections.Generic;
using Hsp.WebNovels.Model.Models;
using Hsp.WebNovels.Model.Dtos;

namespace Hsp.WebNovels.App
{
    internal class Program
    {
        static async Task Main(string[] args)
        {
            await Task.Delay(1);
            //await Task.Run(() => { });

            var builder = WebApplication.CreateBuilder(args);
            var config = builder.Configuration;
            var connectionString = config.GetConnectionString("DBConnectionString");
            SqlSugarBase.Db_ConnectionString = connectionString;
            //Console.WriteLine(connectionString);

            SqlSugarClient db = new(new ConnectionConfig()
            {
                ConfigId = "0",
                DbType = DbType.SqlServer,
                ConnectionString = connectionString,
                IsAutoCloseConnection = true
            });

            ////用来打印Sql方便你调式    
            //db.Aop.OnLogExecuting = (sql, pars) =>
            //{
            //    System.Console.WriteLine(sql + "\r\n" +
            //    db.Utilities.SerializeObject(pars.ToDictionary(it => it.ParameterName, it => it.Value)));
            //    System.Console.WriteLine();
            //};

            {
                //SqlSugarClient client = new(new ConnectionConfig() { ConfigId = "0", DbType = DbType.SqlServer, ConnectionString = connectionString, IsAutoCloseConnection = true });
                ////client.Open();
                //var abc = db.Queryable<Chapter>().ToList();
                //var def = abc;
            }

            Console.WriteLine("Hello, Novels!");
            System.Console.WriteLine("**********************************************************");
            System.Console.WriteLine("");

            var encoding = "gbk";
            encoding = "utf-8";

            var webSite = "https://m.uofglam.com/";
            webSite = "https://www.73zw8.com/";
            webSite = "https://www.kandzww.com/";
            webSite = "https://www.bus6.com/";
            webSite = "https://www.yexiashuge.info/";
            webSite = "https://www.93du.com/";

            var isWebSiteUrlCombine = true; // 是否站点地址合并
            var isNovelUrlCombine = true; // 是否小说地址合并
            var isGetText = false;

            {
                var novelUrl = "https://www.93du.com/dulist/86453/1/";
                novelUrl = "https://www.93du.com/dulist/86453/1/";

                HtmlDocument? htmlAddress = await HtmlDocAsync(novelUrl, encoding);
                if (htmlAddress == null) { return; }

                //using HttpClient httpClient = new();
                //Uri? requestUri = new(novelUrl);
                ////以byte[]获取html
                //byte[] bytes = httpClient.GetByteArrayAsync(requestUri).Result;

                ////var html = GetHtml(novelUrl);
                ////var b = html;
                //return;

                var xpathAddress = "//div[@class='section-box'][2]/ul/li/a";
                var nextAddress = "//div[@class='listpage']/span[@class='right']/a";
                var nextAddress0 = "";
                var nextAddress1 = "";
                if (xpathAddress.Contains('|'))
                {
                    nextAddress0 = xpathAddress.Split("|")[0];
                    nextAddress1 = xpathAddress.Split("|")[1];
                }
                else
                {
                    nextAddress0 = xpathAddress;
                }

                //var nodes1 = htmlAddress.DocumentNode.SelectNodes("//div[@class='section-box']");
                //var count = nodes1.Count();

                //var node2 = htmlAddress.DocumentNode.SelectNodes("//div[@class='section-box'][2]");
                //var def = node2;

                //var nodes1 = htmlAddress.DocumentNode.SelectNodes("//div[@class='section-box'][2]/ul/li/a");
                //var count = nodes1.Count();

                //HtmlDocument? htmlAddress = await HtmlDocAsync(novelUrl, encoding);
                //if (htmlAddress == null) { return; }
                var nodes = htmlAddress.DocumentNode.SelectNodes(xpathAddress);

                foreach (var node in nodes)
                {
                    //await Console.Out.WriteLineAsync(node.Attributes["href"].Value.Trim() + Environment.NewLine);
                }

                var nodeNext = htmlAddress.DocumentNode.SelectSingleNode(nextAddress);
                var url = nodeNext.Attributes["href"].Value.Trim();

                await Console.Out.WriteLineAsync(url);











            }

            {
                List<string> urlParts = new();

                for (int i = 0; i < 10000; i++)
                {
                    var sn = ("000" + i.ToString());
                    sn = sn.Substring(sn.Length - 4, 4);
                    urlParts.Add(sn);
                }

                CancellationTokenSource cts = new();
                ParallelOptions po = new()
                {
                    CancellationToken = cts.Token,
                    MaxDegreeOfParallelism = System.Environment.ProcessorCount
                };

                await Parallel.ForEachAsync(urlParts, po, (Func<string, CancellationToken, ValueTask>)(async (urlPart, _) =>
                //await Parallel.ForEachAsync(urlParts, new ParallelOptions()
                //{
                //    MaxDegreeOfParallelism = 8
                //}, (Func<string, CancellationToken, ValueTask>)(async (urlPart, _) =>
                {
                    //await Task.Delay(1000); Console.WriteLine(chapter);
                    //if (string.IsNullOrEmpty(chapter.ChapterUrl)) return;
                    //var client = SqlSugarBase.GetClientInstance();
                    //await GetNovelContentAsync(client, encoding, webSite, xpathContent, xpathNextPage, chapter, isGetText);

                    await GetWebpageContent(urlPart, encoding);

                }));

                //for (int i = 0; i < 1000; i++)
                //{
                //    var sn = ("00" + i.ToString());
                //    sn = sn.Substring(sn.Length - 3, 3);
                //    var novelUrl = $"https://www.81265.net/news/141519{sn}.html";
                //    var xpathContent = "//div[@class='detail-intro-box']/div[@class='detail-intro']/p";
                //    //xpathContent = "//li[@class='cont'][2]/p";
                //    HtmlDocument? htmlAddress = await HtmlDocAsync(novelUrl, encoding);
                //    if (htmlAddress == null) { continue; }

                //    var titlexPath = "//div[@class='detail-intro-box']/div[@class='hd']/h3";
                //    var titleNode = htmlAddress.DocumentNode.SelectSingleNode(titlexPath);
                //    var title = titleNode.InnerText;

                //    if (!title.Contains("特战华夏崛起")) continue;

                //    await Console.Out.WriteLineAsync(title);
                //    await Console.Out.WriteLineAsync("");

                //    var nodes = htmlAddress.DocumentNode.SelectNodes(xpathContent);

                //    var abc = nodes;

                //    string? content = null;
                //    foreach (var item in nodes)
                //    {
                //        content += item.InnerText + Environment.NewLine;
                //    }

                //    await Console.Out.WriteLineAsync(content);
                //    await Console.Out.WriteLineAsync("");
                //    await Console.Out.WriteLineAsync("");
                //    await Console.Out.WriteLineAsync("");
                //}
            }

            {

                //var novelUrl = "https://www.220book.com/book/22900/6493463.html";
                //var xpathContent = "//div[@id='content']/p";

                //HtmlDocument? htmlAddress = await HtmlDocAsync(novelUrl, encoding);
                //if (htmlAddress == null) { return; }
                //var nodes = htmlAddress.DocumentNode.SelectNodes(xpathContent);

                //var abc = nodes;

                //string? content = null;
                //foreach (var item in nodes)
                //{
                //    content += item.InnerText + Environment.NewLine;
                //}

                //await Console.Out.WriteLineAsync(content);
            }

            {
                //var strSql = string.Format(@"SELECT * FROM [dbo].[Chapters];");

                //List<ChapterDto> dtos = await SqlSugarBase.Db.Ado.SqlQueryAsync<ChapterDto>(strSql);


                //List<WebSite> sites = await SqlSugarBase.Db.Queryable<WebSite>().ToListAsync();

                //NewMethod(sites);

                //var abc = sites;
            }

            {
                /*

                // 1、小说目录
                Stopwatch stopwatch = Stopwatch.StartNew();
                stopwatch.Start();

                var novelUrl = "https://www.uofglam.com/9/9789/";
                var xpathAddress = "//div[@id='list']/dl/dd/a";
                var xpathContent = "//div[@id='chaptercontent']";
                var xpathNextPage = "//a[@id='pb_next']";

                // 七三中文网，爷爷异界造反，我在都市无敌了！
                novelUrl = "https://www.73zw8.com/131_131787/";
                xpathContent = "//div[@id='content']";
                xpathNextPage = "";

                isWebSiteUrlCombine = true; // 是否站点地址合并
                isNovelUrlCombine = false; // 是否小说地址合并

                //// 看点中文网，我都元婴期了，你跟我说开
                //novelUrl = "https://www.kandzww.com/book/71924/";
                //xpathAddress = "//div[@class='chapter']/ul/li/div/a";
                //xpathContent = "//div[@id='text']/p";
                //xpathNextPage = "";

                //// 万和中文
                //novelUrl = "https://www.bus6.com/xszx/192391/";
                //xpathAddress = "//div[@id='list']/dl/dd/a";
                //xpathContent = "//div[@id='content']";
                //xpathNextPage = "";

                //// 夜下书阁
                //novelUrl = "https://www.yexiashuge.info/book/1054519/";
                //xpathAddress = "//div[@class='listmain']/dl/dd/a";
                //xpathContent = "//div[@id='content']";
                //xpathNextPage = "";


                isWebSiteUrlCombine = false; // 是否站点地址合并
                isNovelUrlCombine = true; // 是否小说地址合并

                #region MyRegion

                //using HttpClient httpClient = new();
                //Uri? requestUri = new(novelUrl);httpClient.GetByteArrayAsync(requestUri).Result;
                ////解析html,并输入
                //HtmlDocument htmlDoc = new();
                //htmlDoc.LoadHtml(html);
                //以byte[]获取html
                //byte[]? bytes = await HttpHelper.HttpGetAsync(novelUrl);
                //if (bytes == null) return;
                ////将byte[]重新编码成GB2312;
                //Encoding.RegisterProvider(CodePagesEncodingProvider.Instance);
                //string html = Encoding.GetEncoding("GBK").GetString(bytes);
                ////解析html,并输入
                //HtmlDocument htmlDoc = new();
                //htmlDoc.LoadHtml(html);

                #endregion

                //通过xpath指定页面节点获取节点中对应的内容
                HtmlDocument? htmlAddress = await HtmlDocAsync(novelUrl, encoding);
                if (htmlAddress == null) { return; }
                var nodes = htmlAddress.DocumentNode.SelectNodes(xpathAddress);

                foreach (var item in nodes)
                {
                    //System.Console.WriteLine($"{item.InnerText}");
                    //System.Console.WriteLine($"{item.InnerText.Trim()}，{item.Attributes["href"].Value.Trim()}");

                    var title = item.InnerText;

                    Chapter chapter = new();
                    chapter.Id = Guid.NewGuid().ToString().ToUpper();
                    chapter.NovelId = Guid.NewGuid().ToString().ToUpper();
                    chapter.SourceTitle = title;

                    #region 章节数据

                    ChapterTitle chapterTitle = TitleCleaning(title);
                    chapter.ChapterIdx = chapterTitle.Idx;
                    chapter.ChapterName = chapterTitle.Name;
                    chapter.HeadWord = chapterTitle.HeadWord;
                    chapter.ChapterTitle = chapterTitle.Title;

                    #endregion

                    var chapterUrl = item.Attributes["href"].Value.Trim();
                    if (isWebSiteUrlCombine) chapterUrl = $"{webSite.TrimEnd('/')}{chapterUrl}";
                    if (isNovelUrlCombine)
                    {
                        if (!chapterUrl.StartsWith("/")) chapterUrl = "/" + chapterUrl;
                        chapterUrl = $"{novelUrl.TrimEnd('/')}{chapterUrl}";
                    }
                    chapter.ChapterUrl = chapterUrl;

                    #region MyRegion

                    //HtmlDocument htmlContent = HtmlDoc(chapterUrl, encoding);
                    //var contentNode = htmlContent.DocumentNode.SelectSingleNode(xpathContent);
                    //var content = contentNode.InnerHtml;
                    //content = ContentCleaning(content);

                    //var nextUrl = GetNextUrl(htmlContent, xpathNextPage, webSite);

                    //chapter.NextUrl = nextUrl;

                    //if (!string.IsNullOrEmpty(nextUrl))
                    //{
                    //    var nextContent = GetNextContents(nextUrl, encoding, xpathContent, xpathNextPage, webSite);
                    //    content += nextContent;
                    //}

                    //chapter.WordCount = content.Length;
                    //chapter.ValidChapter = content.Length > 500 ? 1 : 0;

                    #region 小说内容保存

                    //Content chapterContent = new();
                    //chapterContent.ChapterId = chapter.Id;
                    //chapterContent.NovelId = chapter.NovelId;
                    //chapterContent.Contents = content;

                    //db.Insertable(chapterContent).ExecuteCommand();

                    #endregion

                    #endregion

                    chapter.CreateTime = DateTime.Now;

                    var exists = await db.Queryable<Chapter>()
                        .Where(c => c.ChapterUrl == chapterUrl).AnyAsync();

                    if (!exists)
                    {
                        await db.Insertable(chapter).ExecuteCommandAsync();
                    }

                    System.Console.WriteLine(chapter.ChapterTitle);
                }

                stopwatch.Stop();
                Console.WriteLine($"{(stopwatch.ElapsedMilliseconds / 1000.0)}秒");

                */
            }

            {
                /*
                // 2、获取小说内容
                var novelUrl = "https://www.uofglam.com/9/9789/";
                var xpathAddress = "//div[@id='list']/dl/dd/a";
                var xpathContent = "//div[@id='chaptercontent']";
                var xpathNextPage = "//a[@id='pb_next']";

                // 七三中文网，爷爷异界造反，我在都市无敌了！
                novelUrl = "https://www.73zw8.com/131_131787/";
                xpathContent = "//div[@id='content']";
                xpathNextPage = "";

                // 看点中文网，我都元婴期了，你跟我说开
                novelUrl = "https://www.kandzww.com/book/71924/";
                xpathAddress = "//div[@class='chapter']/ul/li/div/a";
                xpathContent = "//div[@id='text']";
                xpathNextPage = "";

                // 郭云曦江珩
                novelUrl = "https://www.yexiashuge.info/book/1054519/";
                xpathAddress = "//div[@class='listmain']/dl/dd/a";
                xpathContent = "//div[@id='content']";
                xpathNextPage = "";

                isWebSiteUrlCombine = false; // 是否站点地址合并
                isNovelUrlCombine = true; // 是否小说地址合并
                isGetText = true; // 是否读取内容文本？

                Stopwatch stopwatch = Stopwatch.StartNew();
                stopwatch.Start();

                #region MyRegion

                //List<Task<int>> tasks = new List<Task<int>>();
                //TaskFactory factory = new TaskFactory();

                //tasks.Add(factory.StartNew<int>(() =>
                //{
                //    //Console.WriteLine("t1"); 
                //    GetNovelContent(db, encoding, webSite, xpathContent, xpathNextPage, chapter).Wait();
                //    return Environment.CurrentManagedThreadId;
                //}));

                //await Console.Out.WriteLineAsync(chapter.ChapterUrl);

                //tasks.ForEach(t => Console.WriteLine("Task:{0}", t.Result));

                //await Task.Run(async () =>
                //{
                //    foreach (var chapter in chapters)
                //    {
                //        if (string.IsNullOrEmpty(chapter.ChapterUrl)) return;

                //        await GetNovelContentAsync(db, encoding, webSite, xpathContent, xpathNextPage, chapter, isGetText);
                //    }
                //});

                #endregion

                List<Chapter> chapters = await db.Queryable<Chapter>().ToListAsync();

                await Parallel.ForEachAsync(chapters, new ParallelOptions()
                {
                    MaxDegreeOfParallelism = 8
                }, async (chapter, _) =>
                {
                    //await Task.Delay(1000); Console.WriteLine(chapter);
                    if (string.IsNullOrEmpty(chapter.ChapterUrl)) return;

                    var client = SqlSugarBase.GetClientInstance();

                    await GetNovelContentAsync(client, encoding, webSite, xpathContent, xpathNextPage, chapter, isGetText);

                });

                #region MyRegion

                // Parallel.ForEachAsync 是正确的异步方式
                // lenovo t440p，4核心8线程，运行时间：99.842/8
                // PC，6核心12线程，运行时间：81.78/8，84.384/12（间隔短）

                //await Task.Run(async () =>{});

                //Parallel.For(0, 10, async i =>
                //{
                //    foreach (var chapter in chapters)
                //    {
                //        if (string.IsNullOrEmpty(chapter.ChapterUrl)) return;

                //        await GetNovelContentAsync(db, encoding, webSite, xpathContent, xpathNextPage, chapter);
                //    }
                //});

                #endregion

                stopwatch.Stop();
                Console.WriteLine($"{(stopwatch.ElapsedMilliseconds / 1000.0)}秒");

                */
            }

            {
                /*
                // 3、输出小说
                Stopwatch stopwatch = Stopwatch.StartNew();
                stopwatch.Start();

                {
                    var fileName = DateTime.Now.ToString("yyyyMMddHHmmss");
                    var novelPath = $@"D:\Share\Text\{fileName}.txt";

                    var strSql = string.Format(@"
                        SELECT a.*, c.[Contents]
                        FROM [dbo].[Chapters] a
                        INNER JOIN [dbo].[Contents] c ON c.ChapterId = a.Id
                        --WHERE (a.NovelId = '')
                        ORDER BY a.ChapterIdx
                        ;");

                    List<ChapterDto> dtos = await db.Ado.SqlQueryAsync<ChapterDto>(strSql);

                    if (File.Exists(novelPath)) File.Delete(novelPath); // 删除文件

                    var sw = File.CreateText(novelPath); // 创建文本

                    sw.WriteLine("");
                    sw.WriteLine("嫡长女她带着空间和全族一起逃荒");
                    sw.WriteLine("");
                    sw.WriteLine("作者：郭云曦江珩");
                    sw.WriteLine("");

                    foreach (var chapter in dtos)
                    {
                        if (chapter.WordCount <= 200) continue; // 短内容不输出

                        sw.WriteLine(string.IsNullOrEmpty(chapter.ChapterTitle) ? "第" + chapter.ChapterIdx + "章 标题缺失" : chapter.ChapterTitle);
                        sw.WriteLine("");
                        sw.WriteLine(chapter.Contents);
                        sw.WriteLine("");
                    }

                    sw.Close();
                }

                stopwatch.Stop();
                Console.WriteLine($"{(stopwatch.ElapsedMilliseconds / 1000.0)}秒");
               */
            }

            System.Console.WriteLine("");
            System.Console.WriteLine("**********************************************************");
            System.Console.WriteLine("Bye Novels!");
            System.Console.ReadKey();
        }

        //private static HtmlParser htmlParser = new HtmlParser();

        public static string GetHtml(string url)
        {
            HttpWebRequest request = (HttpWebRequest)WebRequest.Create(url);

            HttpWebResponse response = (HttpWebResponse)request.GetResponse();

            try
            {
                Stream receive = response.GetResponseStream();

                StreamReader readStream = new StreamReader(receive, Encoding.GetEncoding("GB2312"));

                return readStream.ReadToEnd();
            }

            catch (Exception)
            {
                return "";
            }
        }


        /// <summary>
        /// 获取指定网页的内容
        /// </summary>
        /// <param name="chapter"></param>
        /// <param name="encoding"></param>
        /// <returns></returns>
        private static async Task GetWebpageContent(string chapter, string encoding)
        {
            //var sn = ("00" + i.ToString());
            //sn = sn.Substring(sn.Length - 3, 3);

            var novelUrl = $"https://www.81265.net/news/141519{chapter}.html";
            novelUrl = $"https://www.hnxiake.com/news/64{chapter}.html"; // 太白文学网
            novelUrl = $"http://www.2itcn.com/news/230801/385{chapter}.html"; // 126文学网
            //novelUrl = $"http://www.um5.net/news/10{chapter}.html"; // um5
            novelUrl = $"http://www.d1cy.com/zixun/114{chapter}.html"; // 
            novelUrl = $"https://www.xiakexcx.com/news/63{chapter}.html"; // 
            novelUrl = $"https://www.gdskj.com/news/22{chapter}.html";
            novelUrl = $"http://m.lkxsz.com/ldksw/261731/49{chapter}.html";
            novelUrl = $"http://www.81265.net/news/141{chapter}.html";
            novelUrl = $"http://www.d1cy.com/zixun/113{chapter}.html";
            novelUrl = $"https://m.znwx.cn/book/230803/2{chapter}.html";



            var xpathContent = "//div[@class='detail-intro-box']/div[@class='detail-intro']/p";
            xpathContent = "//li[@class='cont'][2]/p";
            xpathContent = "//div[@class='bd_centerw']/p";
            xpathContent = "//div[@class='detail-intro']/p";
            //xpathContent = "//div[@class='content']/p";
            //xpathContent = "//article[@id='nr']/p";
            //xpathContent = "//div[@class='detail-intro']/p";
            xpathContent = "//div[@class='content']/p";
            xpathContent = "//div[@class='content']/p";


            HtmlDocument? htmlAddress = await HtmlDocAsync(novelUrl, encoding);
            if (htmlAddress == null) { return; }

            var titlexPath = "//div[@class='detail-intro-box']/div[@class='hd']/h3";
            titlexPath = "//li[@class='cont'][2]/h3";
            titlexPath = "//div[@class='bd_centerw']/h3[2]";
            titlexPath = "//div[@class='hd']/h3";
            //titlexPath = "//div[@class='content']/h3";
            titlexPath = "//div[@class='zhong']";
            titlexPath = "//div[@class='hd']/h3";
            titlexPath = "//div[@class='content']/h3";
            titlexPath = "//div[@class='content']/h3";



            var titleNode = htmlAddress.DocumentNode.SelectSingleNode(titlexPath);
            var title = titleNode.InnerText;
            title = title.Replace("&nbsp;&nbsp;", "").Replace("内容试读", "").Replace("免费试读", "").Trim();

            if (!title.Contains("特战华夏崛起") && !title.Contains("特战荣耀"))
            {
                await Console.Out.WriteAsync(".");
                //await Console.Out.WriteLineAsync($"{chapter}-{title}");
                return;
            }

            string expTitle = "([第]{0,1})([○零一二三四五六七八九十百千\\d]{1,})([节章]{0,1}[：:。, ]{0,2})([\\s\\S]*?)";
            var titleChapter = TextHelper.ContentExtract(title, expTitle); // 标题章节数字

            // 阿拉伯数字
            titleChapter = TextHelper.ContentExtract(titleChapter, "([\\d]{1,})");
            titleChapter = titleChapter.Replace(Environment.NewLine, "");
            int.TryParse(titleChapter, out int chapterIdx);

            //if (1==1
            //    //(chapterIdx > 60 && chapterIdx < 65) 
            //    //|| (chapterIdx > 82 && chapterIdx < 85)
            //    || (chapterIdx > 89 && chapterIdx < 94)
            //    || (chapterIdx > 99 && chapterIdx < 113)
            //    || chapterIdx == 77 || chapterIdx == 86
            //    || chapterIdx > 118)
            //{
            //}
            //else
            //{
            //    await Console.Out.WriteLineAsync($"{chapter}-{title}");
            //    return;
            //}

            var contentNodes = htmlAddress.DocumentNode.SelectNodes(xpathContent);

            string? contents = null;
            foreach (var content in contentNodes)
            {
                contents += content.InnerText + Environment.NewLine;
            }

            await Console.Out.WriteLineAsync("");
            await Console.Out.WriteLineAsync(title);
            await Console.Out.WriteLineAsync("");

            await Console.Out.WriteLineAsync(contents);
            await Console.Out.WriteLineAsync("");
            await Console.Out.WriteLineAsync("");
            await Console.Out.WriteLineAsync("");
        }

        private static void NewMethod(List<WebSite> sites)
        {
            foreach (var site in sites)
            {
                site.UpdateTime = DateTime.Now;
            }
        }


        private static async Task GetNovelContentAsync(SqlSugarClient db, string encoding, string webSite, string xpathContent, string xpathNextPage, Chapter chapter, bool isGetText)
        {
            if (string.IsNullOrEmpty(chapter.ChapterUrl))
            {
                return;
            }
            HtmlDocument? htmlContent = await HtmlDocAsync(chapter.ChapterUrl, encoding);
            var contentNode = htmlContent?.DocumentNode.SelectSingleNode(xpathContent);
            var content = isGetText ? contentNode?.InnerText : contentNode?.InnerHtml;
            if (htmlContent == null || content == null)
            {
                return;
            }
            content = ContentCleaning(content);

            if (!string.IsNullOrEmpty(xpathNextPage))
            {
                var nextUrl = GetNextUrl(htmlContent, xpathNextPage, webSite);

                chapter.NextUrl = nextUrl;

                if (!string.IsNullOrEmpty(nextUrl))
                {
                    var nextContent = await GetNextContentsAsync(nextUrl, encoding, xpathContent, xpathNextPage, webSite, isGetText);
                    content += nextContent;
                }
            }

            chapter.WordCount = content.Length;
            chapter.ValidChapter = content.Length > 500 ? 1 : 0;

            chapter.UpdateTime = DateTime.Now;

            await db.Updateable(chapter).ExecuteCommandAsync();

            #region 小说内容保存

            Content chapterContent = await db.Queryable<Content>()
                .Where(c => c.ChapterId == chapter.Id).FirstAsync();

            if (chapterContent == null)
            {
                chapterContent = new();
                chapterContent.ChapterId = chapter.Id;
                //chapterContent.NovelId = chapter.NovelId;
                chapterContent.Contents = content;

                await db.Insertable(chapterContent).ExecuteCommandAsync();
            }
            else
            {
                chapterContent.Contents = content;
                await db.Updateable(chapterContent).ExecuteCommandAsync();
            }

            #endregion

            await Console.Out.WriteLineAsync($"{Environment.CurrentManagedThreadId:00}-{chapter.ChapterTitle}");
        }

        private static async Task<HtmlDocument?> HtmlDocAsync(string url, string encoding)
        {
            //using HttpClient client = new();
            //client.DefaultRequestHeaders.Add("Connection", "Keep-Alive");
            //client.DefaultRequestHeaders.Add("Keep-Alive", "3600");
            //Uri? requestUri = new(url);
            //var b = client.GetByteArrayAsync(requestUri).Result;
            //var c = b;

            //以byte[]获取html
            byte[]? bytes = await HttpHelper.HttpGetAsync(url);
            if (bytes == null) return null;

            //将byte[]重新编码成GB2312;
            Encoding.RegisterProvider(CodePagesEncodingProvider.Instance);
            string html = Encoding.GetEncoding(encoding).GetString(bytes);
            //解析html,并输入
            HtmlDocument htmlDoc = new();
            htmlDoc.LoadHtml(html);

            return htmlDoc;
        }

        // 递归获取下一页内容
        private static async Task<string> GetNextContentsAsync(string nextUrl, string encoding, string xpath, string nextPath, string webSite, bool isGetText)
        {
            HtmlDocument nextHtmlDoc = await HtmlDocAsync(nextUrl, encoding);
            if (nextHtmlDoc == null) return "";
            var nextContentNode = nextHtmlDoc?.DocumentNode.SelectSingleNode(xpath);
            var nextContent = isGetText ? nextContentNode?.InnerText : nextContentNode?.InnerHtml;
            var content = ContentCleaning(nextContent);

            nextUrl = GetNextUrl(nextHtmlDoc, nextPath, webSite);

            if (!string.IsNullOrEmpty(nextUrl))
            {
                content += await GetNextContentsAsync(nextUrl, encoding, xpath, nextPath, webSite, isGetText);
            }

            return content;
        }

        private static HtmlDocument HtmlDoc(string url, string encoding)
        {
            using HttpClient client = new();
            Uri? requestUri = new(url);
            //以byte[]获取html
            byte[] bytes = client.GetByteArrayAsync(requestUri).Result;
            //将byte[]重新编码成GB2312;
            Encoding.RegisterProvider(CodePagesEncodingProvider.Instance);
            string html = Encoding.GetEncoding(encoding).GetString(bytes);
            //解析html,并输入
            HtmlDocument htmlDoc = new();
            htmlDoc.LoadHtml(html);

            return htmlDoc;
        }

        private static ChapterTitle TitleCleaning(string title)
        {
            ChapterTitle chapterTitle = new();

            var chapterTemplate = "第$2章";

            var chapterIdx = 0;
            var titleContent = title;
            string expTitle = "([第]{0,1})([○零一二三四五六七八九十百千\\d]{1,})([节章]{0,1}[：:。, ]{0,2})([\\s\\S]*?)";
            var titleChapter = TextHelper.ContentExtract(title, expTitle); // 标题章节数字

            if (!string.IsNullOrEmpty(titleChapter))
            {
                titleChapter = titleChapter.Replace(Environment.NewLine, "&");
                titleChapter = titleChapter.Split('&')[0];

                titleContent = title.Replace(titleChapter, ""); // 标题名称（除去章节数字）
                titleChapter = titleChapter.Replace("。", "").Replace("：", "");

                var expChineseDig = "([○零一二三四五六七八九十百千]{1,})";
                var strChineseChapter = TextHelper.ContentExtract(titleChapter, expChineseDig); // 章节中文数字 
                strChineseChapter = strChineseChapter.Replace(Environment.NewLine, "&");
                strChineseChapter = strChineseChapter.Split('&')[0];

                if (strChineseChapter.Length == 0)
                {
                    // 阿拉伯数字
                    titleChapter = TextHelper.ContentExtract(titleChapter, "([\\d]{1,})");
                    titleChapter = titleChapter.Replace(Environment.NewLine, "");
                    int.TryParse(titleChapter, out chapterIdx);
                }
                else
                {
                    if (TextHelper.ContentExtract(strChineseChapter, "([十百千]{1,})").Length > 0)
                    {
                        chapterIdx = int.Parse(TextHelper.DecodeMoneyCn(strChineseChapter).ToString());
                    }
                    else
                    {
                        chapterIdx = int.Parse(TextHelper.DecodeSimpleCn(strChineseChapter));
                    }
                }

                if (!string.IsNullOrEmpty(titleContent))
                {
                    titleContent = titleContent.Trim().TrimEnd('.');
                    titleContent = titleContent.TrimStart(','); // 标题前面的半角逗号清理

                    #region 处理标题中“几更”信息

                    if (!string.IsNullOrEmpty(titleContent) && titleContent.Contains('更'))
                    {
                        var exp = "([(（]{1})([\\s\\S]*?)([）)]{1})";
                        var result = TextHelper.ContentExtract(titleContent, exp);

                        if (!string.IsNullOrEmpty(result) && result.Contains('更'))
                        {
                            result = result.TrimEnd('\n').TrimEnd('\r');
                            result = result.Replace("\n", "").Replace("\r", "");
                            titleContent = titleContent.Replace(result, "");
                        }
                    }

                    #endregion

                    titleContent = titleContent.Trim();
                    titleContent = titleContent.Replace("&nbsp;", "");

                    titleContent = titleContent.Replace("（新书求支持）", "");
                    titleContent = titleContent.Replace("（求收藏、求鲜花）", "");
                    titleContent = titleContent.Replace("（求收藏）", "");
                    titleContent = titleContent.Replace("（求订阅）", "");
                    titleContent = titleContent.Replace("（改）", "");

                    //titleContent = titleContent.Replace("（第一更！）", "");
                    //titleContent = titleContent.Replace("（第二更！）", "");
                    //titleContent = titleContent.Replace("（第三更！）", "");
                    //titleContent = titleContent.Replace("（第四更！）", "");
                    //titleContent = titleContent.Replace("（第五更！）", "");
                    //titleContent = titleContent.Replace("（第六更！）", "");
                    //titleContent = titleContent.Replace("（第七更！）", "");
                    //titleContent = titleContent.Replace("（第八更！）", "");
                    //titleContent = titleContent.Replace("（第九更！）", "");

                    //titleContent = titleContent.Replace("（第十更！）", "");
                    //titleContent = titleContent.Replace("（第十一更！）", "");
                    //titleContent = titleContent.Replace("（第十二更！）", "");
                    //titleContent = titleContent.Replace("（第十三更！）", "");
                    //titleContent = titleContent.Replace("（第十四更！）", "");
                    //titleContent = titleContent.Replace("（第十五更！）", "");

                    titleContent = titleContent.Replace("（第一更）", "");
                    titleContent = titleContent.Replace("（第二更）", "");
                    titleContent = titleContent.Replace("（第三更）", "");
                    titleContent = titleContent.Replace("（第二）", "");

                    titleContent = titleContent.Replace("【求鲜花】", "");
                    titleContent = titleContent.Replace("【求首订】", "");
                    titleContent = titleContent.Replace("【鲜花】", "");

                    titleContent = titleContent.Replace("求订阅", "");
                    titleContent = titleContent.Replace("求全定", "");
                    titleContent = titleContent.Replace("求收藏", "");
                    titleContent = titleContent.Replace("求首订", "");

                    titleContent = titleContent.Replace("重复已修改", "");
                    titleContent = titleContent.Replace("补上昨天的", "");

                    titleContent = titleContent.Replace("【】", "").Replace("（）", "").Replace("()", "");

                    //（改）
                }

                // 第$2章
                if (chapterIdx > 0)
                {
                    titleChapter = chapterTemplate.Replace("$2", chapterIdx.ToString());
                }

                if (string.IsNullOrEmpty(titleChapter))
                {
                    titleChapter = "第$2章".Replace("$2", chapterIdx.ToString());
                }

            }


            chapterTitle.Idx = chapterIdx;
            chapterTitle.Name = titleChapter;
            chapterTitle.HeadWord = titleContent;
            chapterTitle.Title = titleChapter + " " + titleContent;

            return chapterTitle;
        }

        private static string ContentCleaning(string content)
        {
            if (string.IsNullOrEmpty(content))
            {
                return string.Empty;
            }
            //content = content.Trim();
            content = content.TrimStart('\r').TrimStart('\n');
            content = content.TrimEnd('\n').TrimStart('\r');

            content = content.Replace("<br><br>", "<br>").Replace("<br>", Environment.NewLine);

            content = content.Replace("&nbsp;", "");
            content = content.Replace("&#12290;", "。");
            content = content.Replace("&#24819;", "想");

            content = content.Replace("\r\n”", "”");
            content = content.Replace("\r\n、", "、");

            content = ContentHelper.RegexReplace("<p[^>]*>([\\s\\S]*?)</p>", content, "");

            //content = content.Replace("(第1/4页)本章未完，请点击&#8595;&#8595;&#8595;继续阅读", "");
            //content = content.Replace("(第2/4页)本章未完，请点击&#8595;&#8595;&#8595;继续阅读", "");
            //content = content.Replace("(第3/4页)本章未完，请点击&#8595;&#8595;&#8595;继续阅读", "");
            //content = content.Replace("(第4/4页)本章未完，请点击&#8595;&#8595;&#8595;继续阅读", "");

            return content;
        }

        /// <summary>
        /// 获取下一页地址
        /// </summary>
        /// <param name="htmlDoc"></param>
        /// <param name="nextPath"></param>
        /// <param name="webSite"></param>
        /// <returns></returns>
        private static string GetNextUrl(HtmlDocument htmlDoc, string nextPath, string webSite)
        {
            var nextNode = htmlDoc.DocumentNode.SelectSingleNode(nextPath);
            var nextUrl = nextNode.Attributes["href"].Value.Trim();
            if (nextUrl.Contains("javascript") || string.IsNullOrEmpty(nextUrl)) return "";
            if (nextUrl.Contains("http")) return nextUrl;
            return $"{webSite}{nextUrl}";
        }

        // 递归获取下一页内容
        private static string GetNextContents(string nextUrl, string encoding, string xpath, string nextPath, string webSite)
        {
            HtmlDocument nextHtmlDoc = HtmlDoc(nextUrl, encoding);
            var nextContentNode = nextHtmlDoc.DocumentNode.SelectSingleNode(xpath);
            if (nextContentNode == null) return "";
            var nextContent = nextContentNode.InnerHtml;
            var content = ContentCleaning(nextContent);

            nextUrl = GetNextUrl(nextHtmlDoc, nextPath, webSite);

            if (!string.IsNullOrEmpty(nextUrl))
            {
                content += GetNextContents(nextUrl, encoding, xpath, nextPath, webSite);
            }

            return content;
        }

        //自动获取网页编码
        private static Encoding GetWebEncoding(string serverUrl)
        {
            WebRequest request = WebRequest.Create(serverUrl);
            WebResponse response = request.GetResponse();
            Stream sr = response.GetResponseStream();
            byte[] buffer = new byte[1200];
            sr.Read(buffer, 0, buffer.Length);
            string head = Encoding.Default.GetString(buffer);
            string regPatt = @"charset\s*=\s*(?<encode>\w+)";
            Regex regEncode = new Regex(regPatt, RegexOptions.IgnoreCase
                | RegexOptions.Compiled);
            string encodname = regEncode.Match(head).Result("${encode}");

            return Encoding.GetEncoding(encodname);
        }

    }
}